import React from "react";
import { useNavigation } from "react-router";
import { useDispatch, useSelector } from "react-redux";
import { RootState } from "#/store";
import { addFile, removeFile } from "#/state/initial-query-slice";
import { SuggestionBubble } from "#/components/features/suggestions/suggestion-bubble";
import { SUGGESTIONS } from "#/utils/suggestions";
import { convertImageToBase64 } from "#/utils/convert-image-to-base-64";
import { ChatInput } from "#/components/features/chat/chat-input";
import { getRandomKey } from "#/utils/get-random-key";
import { cn } from "#/utils/utils";
import { AttachImageLabel } from "../features/images/attach-image-label";
import { ImageCarousel } from "../features/images/image-carousel";
import { UploadImageInput } from "../features/images/upload-image-input";
import { useCreateConversation } from "#/hooks/mutation/use-create-conversation";
import { LoadingSpinner } from "./loading-spinner";

interface TaskFormProps {
  ref: React.RefObject<HTMLFormElement | null>;
}

export function TaskForm({ ref }: TaskFormProps) {
  const dispatch = useDispatch();
  const navigation = useNavigation();

  const { files } = useSelector((state: RootState) => state.initialQuery);

  const [text, setText] = React.useState("");
  const [suggestion, setSuggestion] = React.useState(() => {
    const key = getRandomKey(SUGGESTIONS["non-repo"]);
    return { key, value: SUGGESTIONS["non-repo"][key] };
  });
  const [inputIsFocused, setInputIsFocused] = React.useState(false);
  const { mutate: createConversation, isPending } = useCreateConversation();

  const onRefreshSuggestion = () => {
    const suggestions = SUGGESTIONS["non-repo"];
    // remove current suggestion to avoid refreshing to the same suggestion
    const suggestionCopy = { ...suggestions };
    delete suggestionCopy[suggestion.key];

    const key = getRandomKey(suggestionCopy);
    setSuggestion({ key, value: suggestions[key] });
  };

  const onClickSuggestion = () => {
    setText(suggestion.value);
  };

  const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    const formData = new FormData(event.currentTarget);

    const q = formData.get("q")?.toString();
    createConversation({ q });
  };

  return (
    <div className="flex flex-col gap-1 w-full">
      <form
        ref={ref}
        onSubmit={handleSubmit}
        className="flex flex-col items-center gap-2"
      >
        <SuggestionBubble
          suggestion={suggestion}
          onClick={onClickSuggestion}
          onRefresh={onRefreshSuggestion}
        />
        <div
          className={cn(
            "border border-neutral-600 px-4 rounded-lg text-[17px] leading-5 w-full transition-colors duration-200",
            inputIsFocused ? "bg-neutral-600" : "bg-tertiary",
            "hover:border-neutral-500 focus-within:border-neutral-500",
          )}
        >
          {isPending ? (
            <div className="flex justify-center py-[17px]">
              <LoadingSpinner size="small" />
            </div>
          ) : (
            <ChatInput
              name="q"
              onSubmit={() => {
                if (typeof ref !== "function") ref?.current?.requestSubmit();
              }}
              onChange={(message) => setText(message)}
              onFocus={() => setInputIsFocused(true)}
              onBlur={() => setInputIsFocused(false)}
              onImagePaste={async (imageFiles) => {
                const promises = imageFiles.map(convertImageToBase64);
                const base64Images = await Promise.all(promises);
                base64Images.forEach((base64) => {
                  dispatch(addFile(base64));
                });
              }}
              value={text}
              maxRows={15}
              showButton={!!text}
              className="text-[17px] leading-5 py-[17px]"
              buttonClassName="pb-[17px]"
              disabled={navigation.state === "submitting"}
            />
          )}
        </div>
      </form>
      <UploadImageInput
        onUpload={async (uploadedFiles) => {
          const promises = uploadedFiles.map(convertImageToBase64);
          const base64Images = await Promise.all(promises);
          base64Images.forEach((base64) => {
            dispatch(addFile(base64));
          });
        }}
        label={<AttachImageLabel />}
      />
      {files.length > 0 && (
        <ImageCarousel
          size="large"
          images={files}
          onRemove={(index) => dispatch(removeFile(index))}
        />
      )}
    </div>
  );
}
